﻿/*
 * Copyright (C) 2021. Huawei Device Co., Ltd. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the MIT License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * MIT License for more details.
 */

#include "../stdafx.h"
#include "UIListEx.h"

namespace DuiLib {
const int ISEP_WIDTH_VALUE = 4;

IMPLEMENT_DUICONTROL(CListExUI)

CListExUI::CListExUI()
    : m_pEditUI(nullptr),
      m_pComboBoxUI(nullptr),
      m_bAddMessageFilter(FALSE),
      m_nRow(-1),
      m_nColum(-1),
      m_pXCallback(nullptr)
{}

CListExUI::~CListExUI() {}

LPCTSTR CListExUI::GetClass() const
{
    return _T("XListUI");
}

UINT CListExUI::GetControlFlags() const
{
    return UIFLAG_TABSTOP;
}

LPVOID CListExUI::GetInterface(LPCTSTR pstrName)
{
    if (_tcsicmp(pstrName, _T("ListEx")) == 0) {
        return static_cast<IListOwnerUI *>(this);
    }
    return CListUI::GetInterface(pstrName);
}
BOOL CListExUI::CheckColumEditable(int nColum)
{
    CListContainerHeaderItemUI *pHItem = static_cast<CListContainerHeaderItemUI *>(m_pHeader->GetItemAt(nColum));
    if (pHItem == nullptr) {
        return FALSE;
    }
    return pHItem != nullptr ? pHItem->GetColumeEditable() : FALSE;
}
void CListExUI::InitListCtrl()
{
    if (!m_bAddMessageFilter) {
        GetManager()->AddNotifier(this);
        m_bAddMessageFilter = TRUE;
    }
}
CEditUI *CListExUI::GetEditUI()
{
    if (m_pEditUI == nullptr) {
        m_pEditUI = new CEditUI;
        if (m_pEditUI == nullptr) {
            return nullptr;
        }
        m_pEditUI->SetName(_T("ListEx_Edit"));
        LPCTSTR pDefaultAttributes = GetManager()->GetDefaultAttributeList(_T("Edit"));
        if (pDefaultAttributes) {
            m_pEditUI->ApplyAttributeList(pDefaultAttributes);
        }

        Add(m_pEditUI);
    }
    if (m_pComboBoxUI) {
        RECT rc = { 0, 0, 0, 0 };
        m_pComboBoxUI->SetPos(rc);
    }

    return m_pEditUI;
}

BOOL CListExUI::CheckColumComboBoxable(int nColum)
{
    CListContainerHeaderItemUI *pHItem = static_cast<CListContainerHeaderItemUI *>(m_pHeader->GetItemAt(nColum));
    if (pHItem == nullptr) {
        return FALSE;
    }
    return pHItem != nullptr ? pHItem->GetColumeComboable() : FALSE;
}

CComboBoxUI *CListExUI::GetComboBoxUI()
{
    if (m_pComboBoxUI == nullptr) {
        m_pComboBoxUI = new CComboBoxUI;
        if (m_pComboBoxUI == nullptr) {
            return nullptr;
        }
        m_pComboBoxUI->SetName(_T("ListEx_Combo"));
        LPCTSTR pDefaultAttributes = GetManager()->GetDefaultAttributeList(_T("Combo"));
        if (pDefaultAttributes) {
            m_pComboBoxUI->ApplyAttributeList(pDefaultAttributes);
        }

        Add(m_pComboBoxUI);
    }
    if (m_pEditUI) {
        RECT rc = { 0, 0, 0, 0 };
        m_pEditUI->SetPos(rc);
    }

    return m_pComboBoxUI;
}

BOOL CListExUI::CheckColumCheckBoxable(int nColum)
{
    CControlUI *p = m_pHeader->GetItemAt(nColum);

    // Null pointer dereferences, Dereference null return (stat)
    if (p == nullptr) {
        return FALSE;
    }

    CListContainerHeaderItemUI *pHItem =
        static_cast<CListContainerHeaderItemUI *>(p->GetInterface(_T("ListContainerHeaderItem")));
    if (pHItem == nullptr) {
        return FALSE;
    }
    return pHItem != nullptr ? pHItem->GetColumeCheckable() : FALSE;
}

void CListExUI::Notify(TNotifyUI &msg)
{
    if (msg.pSender == nullptr) {
        return;
    }
    CDuiString strName = msg.pSender->GetName();

    // 复选框
    if (_tcsicmp(msg.sType, _T("listheaditemchecked")) == 0) {
        BOOL bCheck = (BOOL)msg.lParam;
        int nIndex = static_cast<int>(msg.wParam);
        for (int i = 0; i < GetCount(); ++i) {
            CControlUI *p = GetItemAt(i);
            if (p == nullptr) {
                continue;
            }
            CListTextExtElementUI *pLItem =
                static_cast<CListTextExtElementUI *>(p->GetInterface(_T("ListTextExElement")));
            if (pLItem != nullptr) {
                pLItem->SetCheck(bCheck);
            }
        }
    } else if (_tcsicmp(msg.sType, DUI_MSGTYPE_LISTITEMCHECKED) == 0) {
        OnListItemChecked(LOWORD(msg.wParam), HIWORD(msg.wParam), static_cast<BOOL>(msg.lParam));
    }

    // 编辑框、组合框
    if (_tcsicmp(strName, _T("ListEx_Edit")) == 0 && m_pEditUI && m_nRow >= 0 && m_nColum >= 0) {
        if (_tcsicmp(msg.sType, DUI_MSGTYPE_SETFOCUS) == 0) {
        } else if (_tcsicmp(msg.sType, DUI_MSGTYPE_KILLFOCUS) == 0) {
            CDuiString sText = m_pEditUI->GetText();
            CListTextExtElementUI *pRowCtrl = reinterpret_cast<CListTextExtElementUI *>(GetItemAt(m_nRow));
            if (pRowCtrl) {
                pRowCtrl->SetText(m_nColum, sText);
            }

            // 重置当前行列
            SetEditRowAndColum(-1, -1);

            // 隐藏编辑框
            RECT rc = { 0, 0, 0, 0 };
            m_pEditUI->SetPos(rc);
        }
    } else if (_tcsicmp(strName, _T("ListEx_Combo")) == 0 && m_pComboBoxUI && m_nRow >= 0 && m_nColum >= 0) {
        int iCurSel, iOldSel;
        iCurSel = static_cast<int>(msg.wParam);
        iOldSel = static_cast<int>(msg.lParam);

        if (_tcsicmp(msg.sType, DUI_MSGTYPE_SETFOCUS) == 0) {
        } else if (_tcsicmp(msg.sType, DUI_MSGTYPE_KILLFOCUS) == 0) {
        } else if (_tcsicmp(msg.sType, DUI_MSGTYPE_LISTITEMSELECT) == 0 && iOldSel >= 0) {
            CListTextExtElementUI *pRowCtrl = reinterpret_cast<CListTextExtElementUI *>(GetItemAt(m_nRow));
            if (pRowCtrl) {
                pRowCtrl->SetText(m_nColum, m_pComboBoxUI->GetText());
            }

            // 隐藏组合框
            RECT rc = { 0, 0, 0, 0 };
            m_pComboBoxUI->SetPos(rc);
        }
    } else if (_tcsicmp(msg.sType, _T("scroll")) == 0 && (m_pComboBoxUI || m_pEditUI) && m_nRow >= 0 && m_nColum >= 0) {
        HideEditAndComboCtrl();
    }
}
void CListExUI::HideEditAndComboCtrl()
{
    // 隐藏编辑框
    RECT rc = { 0, 0, 0, 0 };
    if (m_pEditUI) {
        m_pEditUI->SetPos(rc);
    }

    if (m_pComboBoxUI) {
        m_pComboBoxUI->SetPos(rc);
    }
}
IListComboCallbackUI *CListExUI::GetTextArrayCallback() const
{
    return m_pXCallback;
}

void CListExUI::SetTextArrayCallback(IListComboCallbackUI *pCallback)
{
    m_pXCallback = pCallback;
}
void CListExUI::OnListItemClicked(int nIndex, int nColum, RECT *lpRCColum, LPCTSTR lpstrText)
{
    RECT rc = { 0, 0, 0, 0 };
    if (m_pComboBoxUI == nullptr || lpRCColum == nullptr) {
        return;
    }
    if (nColum < 0) {
        if (m_pEditUI) {
            m_pEditUI->SetPos(rc);
        }
        if (m_pComboBoxUI) {
            m_pComboBoxUI->SetPos(rc);
        }
    } else {
        if (CheckColumEditable(nColum) && GetEditUI()) {
            // 保存当前行列
            SetEditRowAndColum(nIndex, nColum);

            if (m_pEditUI != nullptr) {
                // 设置文字
                m_pEditUI->SetText(lpstrText);

                // 移动位置
                m_pEditUI->SetVisible(TRUE);
                m_pEditUI->SetPos(*lpRCColum);
            }
        } else if (CheckColumComboBoxable(nColum) && GetComboBoxUI()) {
            // 重置组合框
            m_pComboBoxUI->RemoveAll();

            // 保存当前行列
            SetEditRowAndColum(nIndex, nColum);

            // 设置文字
            m_pComboBoxUI->SetText(lpstrText);

            // 获取
            if (m_pXCallback) {
                m_pXCallback->GetItemComboTextArray(m_pComboBoxUI, nIndex, nColum);
            }

            // 移动位置
            m_pComboBoxUI->SetPos(*lpRCColum);
            m_pComboBoxUI->SetVisible(TRUE);
        } else {
            if (m_pEditUI) {
                m_pEditUI->SetPos(rc);
            }
            if (m_pComboBoxUI) {
                m_pComboBoxUI->SetPos(rc);
            }
        }
    }
}
void CListExUI::OnListItemChecked(int nIndex, int nColum, BOOL bChecked)
{
    CControlUI *p = m_pHeader->GetItemAt(nColum);
    if (p == nullptr) {
        return;
    }
    CListContainerHeaderItemUI *pHItem =
        static_cast<CListContainerHeaderItemUI *>(p->GetInterface(_T("ListContainerHeaderItem")));
    if (pHItem == nullptr) {
        return;
    }

    // 如果选中，那么检查是否全部都处于选中状态
    if (bChecked) {
        BOOL bCheckAll = TRUE;
        for (int i = 0; i < GetCount(); i++) {
            CControlUI *p = GetItemAt(i);
            if (p == nullptr) {
                continue;
            }
            CListTextExtElementUI *pLItem =
                static_cast<CListTextExtElementUI *>(p->GetInterface(_T("ListTextExElement")));
            if (pLItem != nullptr && !pLItem->GetCheck()) {
                bCheckAll = FALSE;
                break;
            }
        }
        if (bCheckAll) {
            pHItem->SetCheck(TRUE);
        } else {
            pHItem->SetCheck(FALSE);
        }
    } else {
        pHItem->SetCheck(FALSE);
    }
}
void CListExUI::DoEvent(TEventUI &event)
{
    if (event.Type == UIEVENT_BUTTONDOWN) {
        HideEditAndComboCtrl();
    }

    CListUI::DoEvent(event);
}
void CListExUI::SetColumItemColor(int nIndex, int nColum, DWORD iBKColor)
{
    CControlUI *p = GetItemAt(nIndex);
    if (p == nullptr) {
        return;
    }
    CListTextExtElementUI *pLItem = static_cast<CListTextExtElementUI *>(p->GetInterface(_T("ListTextExElement")));
    if (pLItem != nullptr) {
        DWORD iTextBkColor = 0xFFFF0000;
        pLItem->SetColumItemColor(nColum, iTextBkColor);
    }
}

BOOL CListExUI::GetColumItemColor(int nIndex, int nColum, DWORD &iBKColor)
{
    CControlUI *p = GetItemAt(nIndex);
    if (p == nullptr) {
        return FALSE;
    }
    CListTextExtElementUI *pLItem = static_cast<CListTextExtElementUI *>(p->GetInterface(_T("ListTextExElement")));
    if (pLItem == nullptr) {
        return FALSE;
    }
    pLItem->GetColumItemColor(nColum, iBKColor);
    return TRUE;
}

IMPLEMENT_DUICONTROL(CListContainerHeaderItemUI)

CListContainerHeaderItemUI::CListContainerHeaderItemUI()
    : m_bDragable(TRUE),
      m_uButtonState(0),
      m_iSepWidth(ISEP_WIDTH_VALUE),
      m_uTextStyle(DT_VCENTER | DT_CENTER | DT_SINGLELINE),
      m_dwTextColor(0),
      m_iFont(-1),
      m_bShowHtml(FALSE),
      m_bEditable(FALSE),
      m_bComboable(FALSE),
      m_bCheckBoxable(FALSE),
      m_uCheckBoxState(0),
      m_bChecked(FALSE),
      m_pOwner(nullptr)
{
    const int txtValue = 2;
    const int minValue = 16;
    SetTextPadding(CDuiRect(txtValue, 0, txtValue, 0));
    ptLastMouse.x = ptLastMouse.y = 0;
    SetMinWidth(minValue);
}

CListContainerHeaderItemUI::~CListContainerHeaderItemUI() {}

LPCTSTR CListContainerHeaderItemUI::GetClass() const
{
    return _T("ListContainerHeaderItem");
}

LPVOID CListContainerHeaderItemUI::GetInterface(LPCTSTR pstrName)
{
    if (_tcsicmp(pstrName, _T("ListContainerHeaderItem")) == 0) {
        return this;
    }
    return CContainerUI::GetInterface(pstrName);
}

UINT CListContainerHeaderItemUI::GetControlFlags() const
{
    if (IsEnabled() && m_iSepWidth != 0) {
        return UIFLAG_SETCURSOR;
    } else {
        return 0;
    }
}

void CListContainerHeaderItemUI::SetEnabled(BOOL bEnable)
{
    CContainerUI::SetEnabled(bEnable == TRUE);
    if (!IsEnabled()) {
        m_uButtonState = 0;
    }
}

BOOL CListContainerHeaderItemUI::IsDragable() const
{
    return m_bDragable;
}

void CListContainerHeaderItemUI::SetDragable(BOOL bDragable)
{
    m_bDragable = bDragable;
    if (!m_bDragable) {
        m_uButtonState &= ~UISTATE_CAPTURED;
    }
}

DWORD CListContainerHeaderItemUI::GetSepWidth() const
{
    return static_cast<DWORD>(m_iSepWidth);
}

void CListContainerHeaderItemUI::SetSepWidth(int iWidth)
{
    m_iSepWidth = iWidth;
}

DWORD CListContainerHeaderItemUI::GetTextStyle() const
{
    return m_uTextStyle;
}

void CListContainerHeaderItemUI::SetTextStyle(UINT uStyle)
{
    m_uTextStyle = uStyle;
    Invalidate();
}

DWORD CListContainerHeaderItemUI::GetTextColor() const
{
    return m_dwTextColor;
}


void CListContainerHeaderItemUI::SetTextColor(DWORD dwTextColor)
{
    m_dwTextColor = dwTextColor;
}

RECT CListContainerHeaderItemUI::GetTextPadding() const
{
    return m_rcTextPadding;
}

void CListContainerHeaderItemUI::SetTextPadding(RECT rc)
{
    m_rcTextPadding = rc;
    Invalidate();
}

void CListContainerHeaderItemUI::SetFont(int index)
{
    m_iFont = index;
}

BOOL CListContainerHeaderItemUI::IsShowHtml()
{
    return m_bShowHtml;
}

void CListContainerHeaderItemUI::SetShowHtml(BOOL bShowHtml)
{
    if (m_bShowHtml == bShowHtml) {
        return;
    }

    m_bShowHtml = bShowHtml;
    Invalidate();
}

LPCTSTR CListContainerHeaderItemUI::GetNormalImage() const
{
    return m_sNormalImage;
}

void CListContainerHeaderItemUI::SetNormalImage(LPCTSTR pStrImage)
{
    m_sNormalImage = pStrImage;
    Invalidate();
}

LPCTSTR CListContainerHeaderItemUI::GetHotImage() const
{
    return m_sHotImage;
}

void CListContainerHeaderItemUI::SetHotImage(LPCTSTR pStrImage)
{
    m_sHotImage = pStrImage;
    Invalidate();
}

LPCTSTR CListContainerHeaderItemUI::GetPushedImage() const
{
    return m_sPushedImage;
}

void CListContainerHeaderItemUI::SetPushedImage(LPCTSTR pStrImage)
{
    m_sPushedImage = pStrImage;
    Invalidate();
}

LPCTSTR CListContainerHeaderItemUI::GetFocusedImage() const
{
    return m_sFocusedImage;
}

void CListContainerHeaderItemUI::SetFocusedImage(LPCTSTR pStrImage)
{
    m_sFocusedImage = pStrImage;
    Invalidate();
}

LPCTSTR CListContainerHeaderItemUI::GetSepImage() const
{
    return m_sSepImage;
}

void CListContainerHeaderItemUI::SetSepImage(LPCTSTR pStrImage)
{
    m_sSepImage = pStrImage;
    Invalidate();
}

void CListContainerHeaderItemUI::SetAttribute(LPCTSTR pstrName, LPCTSTR pstrValue)
{
    const int colorRadix = 16;
    const int txtRadix = 10;
    if (pstrValue == nullptr) {
        return;
    }
    if (_tcsicmp(pstrName, _T("dragable")) == 0) {
        SetDragable(_tcsicmp(pstrValue, _T("true")) == 0);
    } else if (_tcsicmp(pstrName, _T("sepwidth")) == 0) {
        SetSepWidth(_ttoi(pstrValue));
    } else if (_tcsicmp(pstrName, _T("align")) == 0) {
        if (_tcsstr(pstrValue, _T("left")) != nullptr) {
            m_uTextStyle &= ~(DT_CENTER | DT_RIGHT);
            m_uTextStyle |= DT_LEFT;
        }
        if (_tcsstr(pstrValue, _T("center")) != nullptr) {
            m_uTextStyle &= ~(DT_LEFT | DT_RIGHT);
            m_uTextStyle |= DT_CENTER;
        }
        if (_tcsstr(pstrValue, _T("right")) != nullptr) {
            m_uTextStyle &= ~(DT_LEFT | DT_CENTER);
            m_uTextStyle |= DT_RIGHT;
        }
    } else if (_tcsicmp(pstrName, _T("endellipsis")) == 0) {
        if (_tcsicmp(pstrValue, _T("true")) == 0) {
            m_uTextStyle |= DT_END_ELLIPSIS;
        } else {
            m_uTextStyle &= ~DT_END_ELLIPSIS;
        }
    } else if (_tcsicmp(pstrName, _T("font")) == 0) {
        SetFont(_ttoi(pstrValue));
    } else if (_tcsicmp(pstrName, _T("textcolor")) == 0) {
        if (*pstrValue == _T('#')) {
            pstrValue = ::CharNext(pstrValue);
        }
        LPTSTR pstr = nullptr;
        DWORD clrColor = _tcstoul(pstrValue, &pstr, colorRadix);
        SetTextColor(clrColor);
    } else if (_tcsicmp(pstrName, _T("textpadding")) == 0) {
        RECT rcTextPadding = { 0 };
        LPTSTR pstr = nullptr;
        rcTextPadding.left = _tcstol(pstrValue, &pstr, txtRadix);
        rcTextPadding.top = _tcstol(pstr + 1, &pstr, txtRadix);
        rcTextPadding.right = _tcstol(pstr + 1, &pstr, txtRadix);
        rcTextPadding.bottom = _tcstol(pstr + 1, &pstr, txtRadix);
        SetTextPadding(rcTextPadding);
    } else if (_tcsicmp(pstrName, _T("showhtml")) == 0) {
        SetShowHtml(_tcsicmp(pstrValue, _T("true")) == 0);
    } else if (_tcsicmp(pstrName, _T("normalimage")) == 0) {
        SetNormalImage(pstrValue);
    } else if (_tcsicmp(pstrName, _T("hotimage")) == 0) {
        SetHotImage(pstrValue);
    } else if (_tcsicmp(pstrName, _T("pushedimage")) == 0) {
        SetPushedImage(pstrValue);
    } else if (_tcsicmp(pstrName, _T("focusedimage")) == 0) {
        SetFocusedImage(pstrValue);
    } else if (_tcsicmp(pstrName, _T("sepimage")) == 0) {
        SetSepImage(pstrValue);

    } else if (_tcsicmp(pstrName, _T("editable")) == 0) {
        SetColumeEditable(_tcsicmp(pstrValue, _T("true")) == 0);
    } else if (_tcsicmp(pstrName, _T("comboable")) == 0) {
        SetColumeComboable(_tcsicmp(pstrValue, _T("true")) == 0);
    } else if (_tcsicmp(pstrName, _T("checkable")) == 0) {
        SetColumeCheckable(_tcsicmp(pstrValue, _T("true")) == 0);
    } else if (_tcsicmp(pstrName, _T("checkboxwidth")) == 0) {
        SetCheckBoxWidth(_ttoi(pstrValue));
    } else if (_tcsicmp(pstrName, _T("checkboxheight")) == 0) {
        SetCheckBoxHeight(_ttoi(pstrValue));
    } else if (_tcsicmp(pstrName, _T("checkboxnormalimage")) == 0) {
        SetCheckBoxNormalImage(pstrValue);
    } else if (_tcsicmp(pstrName, _T("checkboxhotimage")) == 0) {
        SetCheckBoxHotImage(pstrValue);
    } else if (_tcsicmp(pstrName, _T("checkboxpushedimage")) == 0) {
        SetCheckBoxPushedImage(pstrValue);
    } else if (_tcsicmp(pstrName, _T("checkboxfocusedimage")) == 0) {
        SetCheckBoxFocusedImage(pstrValue);
    } else if (_tcsicmp(pstrName, _T("checkboxdisabledimage")) == 0) {
        SetCheckBoxDisabledImage(pstrValue);
    } else if (_tcsicmp(pstrName, _T("checkboxselectedimage")) == 0) {
        SetCheckBoxSelectedImage(pstrValue);
    } else if (_tcsicmp(pstrName, _T("checkboxforeimage")) == 0) {
        SetCheckBoxForeImage(pstrValue);
    } else {
        CContainerUI::SetAttribute(pstrName, pstrValue);
    }
}

void CListContainerHeaderItemUI::DoEvent(TEventUI &event)
{
    if (!IsMouseEnabled() && event.Type > UIEVENT__MOUSEBEGIN && event.Type < UIEVENT__MOUSEEND) {
        if (m_pParent != nullptr) {
            m_pParent->DoEvent(event);
        } else {
            CContainerUI::DoEvent(event);
        }
        return;
    }
    if (m_pManager == nullptr) {
        return;
    }
    // CheckBoxAble
    if (m_bCheckBoxable) {
        RECT rcCheckBox;
        GetCheckBoxRect(rcCheckBox);

        if (event.Type == UIEVENT_BUTTONDOWN || event.Type == UIEVENT_DBLCLICK) {
            if (::PtInRect(&rcCheckBox, event.ptMouse)) {
                m_uCheckBoxState |= UISTATE_PUSHED | UISTATE_CAPTURED;
                Invalidate();
            }
        } else if (event.Type == UIEVENT_MOUSEMOVE) {
            if ((m_uCheckBoxState & UISTATE_CAPTURED) != 0) {
                if (::PtInRect(&rcCheckBox, event.ptMouse)) {
                    m_uCheckBoxState |= UISTATE_PUSHED;
                } else {
                    m_uCheckBoxState &= ~UISTATE_PUSHED;
                }
                Invalidate();
            } else if (::PtInRect(&rcCheckBox, event.ptMouse)) {
                m_uCheckBoxState |= UISTATE_HOT;
                Invalidate();
            } else {
                m_uCheckBoxState &= ~UISTATE_HOT;
                Invalidate();
            }
        } else if (event.Type == UIEVENT_BUTTONUP) {
            if ((m_uCheckBoxState & UISTATE_CAPTURED) != 0) {
                if (::PtInRect(&rcCheckBox, event.ptMouse)) {
                    SetCheck(!GetCheck());
                    CContainerUI *pOwner = reinterpret_cast<CContainerUI *>(m_pParent);
                    if (pOwner) {
                        m_pManager->SendNotify(this, DUI_MSGTYPE_LISTHEADITEMCHECKED, pOwner->GetItemIndex(this),
                            m_bChecked);
                    }
                }
                m_uCheckBoxState &= ~(UISTATE_PUSHED | UISTATE_CAPTURED);
                Invalidate();
            } else if (::PtInRect(&rcCheckBox, event.ptMouse)) {
            }
        } else if (event.Type == UIEVENT_MOUSEENTER) {
            if (::PtInRect(&rcCheckBox, event.ptMouse)) {
                m_uCheckBoxState |= UISTATE_HOT;
                Invalidate();
            }
        } else if (event.Type == UIEVENT_MOUSELEAVE) {
            m_uCheckBoxState &= ~UISTATE_HOT;
            Invalidate();
        }
    }

    if (event.Type == UIEVENT_SETFOCUS) {
        Invalidate();
    }
    if (event.Type == UIEVENT_KILLFOCUS) {
        Invalidate();
    }
    const int stepValue = 4;
    if (event.Type == UIEVENT_BUTTONDOWN || event.Type == UIEVENT_DBLCLICK) {
        if (!IsEnabled()) {
            return;
        }
        RECT rcSeparator = GetThumbRect();
        if (m_iSepWidth >= 0) {
            rcSeparator.left -= stepValue;
        } else {
            rcSeparator.right += stepValue;
        }
        if (::PtInRect(&rcSeparator, event.ptMouse)) {
            if (m_bDragable) {
                m_uButtonState |= UISTATE_CAPTURED;
                ptLastMouse = event.ptMouse;
            }
        } else {
            m_uButtonState |= UISTATE_PUSHED;
            m_pManager->SendNotify(this, DUI_MSGTYPE_LISTHEADERCLICK);
            Invalidate();
        }
        return;
    }
    if (event.Type == UIEVENT_BUTTONUP) {
        if ((m_uButtonState & UISTATE_CAPTURED) != 0) {
            m_uButtonState &= ~UISTATE_CAPTURED;
            if (GetParent()) {
                GetParent()->NeedParentUpdate();
            }
        } else if ((m_uButtonState & UISTATE_PUSHED) != 0) {
            m_uButtonState &= ~UISTATE_PUSHED;
            Invalidate();
        }
        return;
    }
    if (event.Type == UIEVENT_MOUSEMOVE) {
        if ((m_uButtonState & UISTATE_CAPTURED) != 0) {
            RECT rc = m_rcItem;
            if (m_iSepWidth >= 0) {
                rc.right -= ptLastMouse.x - event.ptMouse.x;
            } else {
                rc.left -= ptLastMouse.x - event.ptMouse.x;
            }

            if (rc.right - rc.left > GetMinWidth()) {
                m_cxyFixed.cx = rc.right - rc.left;
                ptLastMouse = event.ptMouse;
                if (GetParent()) {
                    GetParent()->NeedParentUpdate();
                }
            }
        }
        return;
    }
    if (event.Type == UIEVENT_SETCURSOR) {
        RECT rcSeparator = GetThumbRect();
        if (m_iSepWidth >= 0) {
            rcSeparator.left -= stepValue;
        } else {
            rcSeparator.right += stepValue;
        }
        if (IsEnabled() && m_bDragable && ::PtInRect(&rcSeparator, event.ptMouse)) {
            ::SetCursor(::LoadCursor(nullptr, MAKEINTRESOURCE(IDC_SIZEWE)));
            return;
        }
    }
    if (event.Type == UIEVENT_MOUSEENTER) {
        if (IsEnabled()) {
            m_uButtonState |= UISTATE_HOT;
            Invalidate();
        }
        return;
    }
    if (event.Type == UIEVENT_MOUSELEAVE) {
        if (IsEnabled()) {
            m_uButtonState &= ~UISTATE_HOT;
            Invalidate();
        }
        return;
    }
    CContainerUI::DoEvent(event);
}

SIZE CListContainerHeaderItemUI::EstimateSize(SIZE szAvailable)
{
    const int stepValue = 14;
    if (m_cxyFixed.cy == 0) {
        return CDuiSize(m_cxyFixed.cx, m_pManager->GetDefaultFontInfo()->tm.tmHeight + stepValue);
    }
    return CContainerUI::EstimateSize(szAvailable);
}

RECT CListContainerHeaderItemUI::GetThumbRect() const
{
    if (m_iSepWidth >= 0) {
        return CDuiRect(m_rcItem.right - m_iSepWidth, m_rcItem.top, m_rcItem.right, m_rcItem.bottom);
    } else {
        return CDuiRect(m_rcItem.left, m_rcItem.top, m_rcItem.left - m_iSepWidth, m_rcItem.bottom);
    }
}

void CListContainerHeaderItemUI::PaintStatusImage(HDC hDC)
{
    // HeadItem Bkgnd
    if (IsFocused()) {
        m_uButtonState |= UISTATE_FOCUSED;
    } else {
        m_uButtonState &= ~UISTATE_FOCUSED;
    }

    if ((m_uButtonState & UISTATE_PUSHED) != 0) {
        if (m_sPushedImage.IsEmpty() && !m_sNormalImage.IsEmpty()) {
            DrawImage(hDC, (LPCTSTR)m_sNormalImage);
        }
        if (!DrawImage(hDC, (LPCTSTR)m_sPushedImage)) {
        }
    } else if ((m_uButtonState & UISTATE_HOT) != 0) {
        if (m_sHotImage.IsEmpty() && !m_sNormalImage.IsEmpty()) {
            DrawImage(hDC, (LPCTSTR)m_sNormalImage);
        }
        if (!DrawImage(hDC, (LPCTSTR)m_sHotImage)) {
        }
    } else if ((m_uButtonState & UISTATE_FOCUSED) != 0) {
        if (m_sFocusedImage.IsEmpty() && !m_sNormalImage.IsEmpty()) {
            DrawImage(hDC, (LPCTSTR)m_sNormalImage);
        }
        if (!DrawImage(hDC, (LPCTSTR)m_sFocusedImage)) {
        }
    } else {
        if (!m_sNormalImage.IsEmpty()) {
            if (!DrawImage(hDC, (LPCTSTR)m_sNormalImage)) {
            }
        }
    }

    if (!m_sSepImage.IsEmpty()) {
        RECT rcThumb = GetThumbRect();
        rcThumb.left -= m_rcItem.left;
        rcThumb.top -= m_rcItem.top;
        rcThumb.right -= m_rcItem.left;
        rcThumb.bottom -= m_rcItem.top;

        m_sSepImageModify.Empty();
        m_sSepImageModify.SmallFormat(_T("dest='%d,%d,%d,%d'"), rcThumb.left, rcThumb.top, rcThumb.right,
            rcThumb.bottom);
        if (!DrawImage(hDC, (LPCTSTR)m_sSepImage, (LPCTSTR)m_sSepImageModify)) {
        }
    }

    if (m_bCheckBoxable) {
        m_uCheckBoxState &= ~UISTATE_PUSHED;

        if ((m_uCheckBoxState & UISTATE_SELECTED) != 0) {
            if (!m_sCheckBoxSelectedImage.IsEmpty()) {
                if (!DrawCheckBoxImage(hDC, (LPCTSTR)m_sCheckBoxSelectedImage)) {
                } else {
                    goto Label_ForeImage;
                }
            }
        }

        if (IsFocused()) {
            m_uCheckBoxState |= UISTATE_FOCUSED;
        } else {
            m_uCheckBoxState &= ~UISTATE_FOCUSED;
        }
        if (!IsEnabled()) {
            m_uCheckBoxState |= UISTATE_DISABLED;
        } else {
            m_uCheckBoxState &= ~UISTATE_DISABLED;
        }

        if ((m_uCheckBoxState & UISTATE_DISABLED) != 0) {
            if (!m_sCheckBoxDisabledImage.IsEmpty()) {
                if (!DrawCheckBoxImage(hDC, (LPCTSTR)m_sCheckBoxDisabledImage)) {
                } else {
                    return;
                }
            }
        } else if ((m_uCheckBoxState & UISTATE_PUSHED) != 0) {
            if (!m_sCheckBoxPushedImage.IsEmpty()) {
                if (!DrawCheckBoxImage(hDC, (LPCTSTR)m_sCheckBoxPushedImage)) {
                } else {
                    return;
                }
            }
        } else if ((m_uCheckBoxState & UISTATE_HOT) != 0) {
            if (!m_sCheckBoxHotImage.IsEmpty()) {
                if (!DrawCheckBoxImage(hDC, (LPCTSTR)m_sCheckBoxHotImage)) {
                } else {
                    return;
                }
            }
        } else if ((m_uCheckBoxState & UISTATE_FOCUSED) != 0) {
            if (!m_sCheckBoxFocusedImage.IsEmpty()) {
                if (!DrawCheckBoxImage(hDC, (LPCTSTR)m_sCheckBoxFocusedImage)) {
                } else {
                    return;
                }
            }
        }

        if (!m_sCheckBoxNormalImage.IsEmpty()) {
            if (!DrawCheckBoxImage(hDC, (LPCTSTR)m_sCheckBoxNormalImage)) {
            } else {
                return;
            }
        }

    Label_ForeImage:
        if (!m_sCheckBoxForeImage.IsEmpty()) {
            if (!DrawCheckBoxImage(hDC, (LPCTSTR)m_sCheckBoxForeImage)) {
            }
        }
    }
}

void CListContainerHeaderItemUI::PaintText(HDC hDC)
{
    if (m_pManager == nullptr) {
        return;
    }
    if (m_dwTextColor == 0) {
        m_dwTextColor = m_pManager->GetDefaultFontColor();
    }

    RECT rcText = m_rcItem;
    rcText.left += m_rcTextPadding.left;
    rcText.top += m_rcTextPadding.top;
    rcText.right -= m_rcTextPadding.right;
    rcText.bottom -= m_rcTextPadding.bottom;
    if (m_bCheckBoxable) {
        RECT rcCheck;
        GetCheckBoxRect(rcCheck);
        rcText.left += (rcCheck.right - rcCheck.left);
    }

    CDuiString sText = GetText();
    if (sText.IsEmpty()) {
        return;
    }

    int nLinks = 0;
    if (m_bShowHtml) {
        CRenderEngine::DrawHtmlText(hDC, m_pManager, rcText, sText, m_dwTextColor, m_iFont, nullptr, nullptr, nLinks,
            DT_SINGLELINE | m_uTextStyle);
    } else {
        CRenderEngine::DrawText(hDC, m_pManager, rcText, sText, m_dwTextColor, m_iFont, DT_SINGLELINE | m_uTextStyle);
    }
}

BOOL CListContainerHeaderItemUI::GetColumeEditable()
{
    return m_bEditable;
}

void CListContainerHeaderItemUI::SetColumeEditable(BOOL bEnable)
{
    m_bEditable = bEnable;
}

BOOL CListContainerHeaderItemUI::GetColumeComboable()
{
    return m_bComboable;
}

void CListContainerHeaderItemUI::SetColumeComboable(BOOL bEnable)
{
    m_bComboable = bEnable;
}

BOOL CListContainerHeaderItemUI::GetColumeCheckable()
{
    return m_bCheckBoxable;
}
void CListContainerHeaderItemUI::SetColumeCheckable(BOOL bEnable)
{
    m_bCheckBoxable = bEnable;
}
void CListContainerHeaderItemUI::SetCheck(BOOL bCheck)
{
    if (m_bChecked == bCheck) {
        return;
    }
    m_bChecked = bCheck;
    if (m_bChecked) {
        m_uCheckBoxState |= UISTATE_SELECTED;
    } else {
        m_uCheckBoxState &= ~UISTATE_SELECTED;
    }
    Invalidate();
}

BOOL CListContainerHeaderItemUI::GetCheck()
{
    return m_bChecked;
}
BOOL CListContainerHeaderItemUI::DrawCheckBoxImage(HDC hDC, LPCTSTR pStrImage, LPCTSTR pStrModify)
{
    RECT rcCheckBox;
    GetCheckBoxRect(rcCheckBox);
    return CRenderEngine::DrawImageString(hDC, m_pManager, rcCheckBox, m_rcPaint, pStrImage, pStrModify);
}
LPCTSTR CListContainerHeaderItemUI::GetCheckBoxNormalImage()
{
    return m_sCheckBoxNormalImage;
}

void CListContainerHeaderItemUI::SetCheckBoxNormalImage(LPCTSTR pStrImage)
{
    m_sCheckBoxNormalImage = pStrImage;
}

LPCTSTR CListContainerHeaderItemUI::GetCheckBoxHotImage()
{
    return m_sCheckBoxHotImage;
}

void CListContainerHeaderItemUI::SetCheckBoxHotImage(LPCTSTR pStrImage)
{
    m_sCheckBoxHotImage = pStrImage;
}

LPCTSTR CListContainerHeaderItemUI::GetCheckBoxPushedImage()
{
    return m_sCheckBoxPushedImage;
}

void CListContainerHeaderItemUI::SetCheckBoxPushedImage(LPCTSTR pStrImage)
{
    m_sCheckBoxPushedImage = pStrImage;
}

LPCTSTR CListContainerHeaderItemUI::GetCheckBoxFocusedImage()
{
    return m_sCheckBoxFocusedImage;
}

void CListContainerHeaderItemUI::SetCheckBoxFocusedImage(LPCTSTR pStrImage)
{
    m_sCheckBoxFocusedImage = pStrImage;
}

LPCTSTR CListContainerHeaderItemUI::GetCheckBoxDisabledImage()
{
    return m_sCheckBoxDisabledImage;
}

void CListContainerHeaderItemUI::SetCheckBoxDisabledImage(LPCTSTR pStrImage)
{
    m_sCheckBoxDisabledImage = pStrImage;
}
LPCTSTR CListContainerHeaderItemUI::GetCheckBoxSelectedImage()
{
    return m_sCheckBoxSelectedImage;
}

void CListContainerHeaderItemUI::SetCheckBoxSelectedImage(LPCTSTR pStrImage)
{
    m_sCheckBoxSelectedImage = pStrImage;
}
LPCTSTR CListContainerHeaderItemUI::GetCheckBoxForeImage()
{
    return m_sCheckBoxForeImage;
}

void CListContainerHeaderItemUI::SetCheckBoxForeImage(LPCTSTR pStrImage)
{
    m_sCheckBoxForeImage = pStrImage;
}
int CListContainerHeaderItemUI::GetCheckBoxWidth() const
{
    return m_cxyCheckBox.cx;
}

void CListContainerHeaderItemUI::SetCheckBoxWidth(int cx)
{
    if (cx < 0)
        return;
    m_cxyCheckBox.cx = cx;
}

int CListContainerHeaderItemUI::GetCheckBoxHeight() const
{
    return m_cxyCheckBox.cy;
}

void CListContainerHeaderItemUI::SetCheckBoxHeight(int cy)
{
    if (cy < 0)
        return;
    m_cxyCheckBox.cy = cy;
}
void CListContainerHeaderItemUI::GetCheckBoxRect(RECT &rc)
{
    const int leftStep = 6;
    const int multiples = 2;
    SecureZeroMemory(&rc, sizeof(rc));
    int nItemHeight = m_rcItem.bottom - m_rcItem.top;
    rc.left = m_rcItem.left + leftStep;
    rc.top = m_rcItem.top + (nItemHeight - GetCheckBoxHeight()) / multiples;
    rc.right = rc.left + GetCheckBoxWidth();
    rc.bottom = rc.top + GetCheckBoxHeight();
}

void CListContainerHeaderItemUI::SetOwner(CContainerUI *pOwner)
{
    m_pOwner = pOwner;
}
CContainerUI *CListContainerHeaderItemUI::GetOwner()
{
    return m_pOwner;
}
// ///////////////////////////////////////////////////////////////////////////////////
//
//
IMPLEMENT_DUICONTROL(CListTextExtElementUI)

CListTextExtElementUI::CListTextExtElementUI()
    : m_nLinks(0), m_nHoverLink(-1), m_pOwner(nullptr), m_uCheckBoxState(0), m_bChecked(FALSE)
{
    ::ZeroMemory(&m_rcLinks, sizeof(m_rcLinks));
    m_cxyCheckBox.cx = m_cxyCheckBox.cy = 0;

    ::ZeroMemory(&ColumCorlorArray, sizeof(ColumCorlorArray));
}

CListTextExtElementUI::~CListTextExtElementUI()
{
    CDuiString *pText = nullptr;
    for (int it = 0; it < m_aTexts.GetSize(); it++) {
        pText = static_cast<CDuiString *>(m_aTexts.GetAt(it));
        if (pText)
            delete pText;
    }
    m_aTexts.Empty();
}

LPCTSTR CListTextExtElementUI::GetClass() const
{
    return _T("ListTextExElementUI");
}

LPVOID CListTextExtElementUI::GetInterface(LPCTSTR pstrName)
{
    if (_tcsicmp(pstrName, _T("ListTextExElement")) == 0)
        return static_cast<CListTextExtElementUI *>(this);
    return CListLabelElementUI::GetInterface(pstrName);
}

UINT CListTextExtElementUI::GetControlFlags() const
{
    return static_cast<UINT>(UIFLAG_WANTRETURN | ((IsEnabled() && m_nLinks > 0) ? UIFLAG_SETCURSOR : 0));
}

LPCTSTR CListTextExtElementUI::GetText(int iIndex)
{
    CDuiString *pText = static_cast<CDuiString *>(m_aTexts.GetAt(iIndex));
    if (pText)
        return pText->GetData();
    return nullptr;
}

void CListTextExtElementUI::SetText(int iIndex, LPCTSTR pstrText)
{
#ifdef SWITCH_LANGUAGE_TEST
    CDuiString text(pstrText);
    vector<DuiLib::CDuiString> valueList = text.Split(L"@UI@");
    const int containSize = 2;
    if (valueList.size() == containSize) { // 确认容器的大小
        pstrText = valueList[0]; // 获取容器的第一个元素
    }
#endif
    if (m_pOwner == nullptr) {
        return;
    }
    TListInfoUI *pInfo = m_pOwner->GetListInfo();
    if (pInfo == nullptr) {
        return;
    }
    if (iIndex < 0 || iIndex >= pInfo->nColumns)
        return;
    while (m_aTexts.GetSize() < pInfo->nColumns) {
        m_aTexts.Add(nullptr);
    }

    CDuiString *pText = static_cast<CDuiString *>(m_aTexts.GetAt(iIndex));
    if ((pText == nullptr && pstrText == nullptr) || (pText && *pText == pstrText)) {
        return;
    }

    if (pText) {
        pText->Assign(pstrText);
    } else {
        m_aTexts.SetAt(iIndex, new CDuiString(pstrText));
    }
    Invalidate();
}

void CListTextExtElementUI::SetOwner(CControlUI *pOwner)
{
    if (pOwner == nullptr) {
        return;
    }
    CListElementUI::SetOwner(pOwner);
    m_pOwner = static_cast<CListUI *>(pOwner->GetInterface(_T("List")));
}

CDuiString *CListTextExtElementUI::GetLinkContent(int iIndex)
{
    if (iIndex >= 0 && iIndex < m_nLinks) {
        return &m_sLinks[iIndex];
    }
    return nullptr;
}

void CListTextExtElementUI::DoEvent(TEventUI &event)
{
    if (!IsMouseEnabled() && event.Type > UIEVENT__MOUSEBEGIN && event.Type < UIEVENT__MOUSEEND) {
        if (m_pOwner != nullptr) {
            m_pOwner->DoEvent(event);
        } else {
            CListLabelElementUI::DoEvent(event);
        }
        return;
    }
    if (m_pManager == nullptr) {
        return;
    }
    // When you hover over a link
    if (event.Type == UIEVENT_SETCURSOR) {
        for (int i = 0; i < m_nLinks; i++) {
            if (::PtInRect(&m_rcLinks[i], event.ptMouse)) {
                ::SetCursor(::LoadCursor(nullptr, MAKEINTRESOURCE(IDC_HAND)));
                return;
            }
        }
    }
    if (event.Type == UIEVENT_BUTTONUP && IsEnabled()) {
        for (int i = 0; i < m_nLinks; i++) {
            if (::PtInRect(&m_rcLinks[i], event.ptMouse)) {
                m_pManager->SendNotify(this, DUI_MSGTYPE_LINK, i);
                return;
            }
        }
    }
    if (m_nLinks > 0 && event.Type == UIEVENT_MOUSEMOVE) {
        int nHoverLink = -1;
        for (int i = 0; i < m_nLinks; i++) {
            if (::PtInRect(&m_rcLinks[i], event.ptMouse)) {
                nHoverLink = i;
                break;
            }
        }

        if (m_nHoverLink != nHoverLink) {
            Invalidate();
            m_nHoverLink = nHoverLink;
        }
    }
    if (m_nLinks > 0 && event.Type == UIEVENT_MOUSELEAVE) {
        if (m_nHoverLink != -1) {
            Invalidate();
            m_nHoverLink = -1;
        }
    }

    // 检查是否需要显示编辑框或者组合框
    const int axesValue = -2; // x,y的值
    if (m_pOwner == nullptr) {
        return;
    }
    CListExUI *pListCtrl = reinterpret_cast<CListExUI *>(m_pOwner);
    if (pListCtrl == nullptr) {
        return;
    }
    int nColum = HitTestColum(event.ptMouse);
    if (event.Type == UIEVENT_BUTTONDOWN && m_pOwner->IsFocused()) {
        RECT rc = { 0, 0, 0, 0 };
        if (nColum >= 0) {
            GetColumRect(nColum, rc);
            ::InflateRect(&rc, axesValue, axesValue);
        }

        pListCtrl->OnListItemClicked(GetIndex(), nColum, &rc, GetText(nColum));
    }

    // 检查是否需要显示CheckBox
    TListInfoUI *pInfo = m_pOwner->GetListInfo();
    if (pInfo == nullptr) {
        return;
    }
    for (int i = 0; i < pInfo->nColumns; i++) {
        if (pListCtrl->CheckColumCheckBoxable(i)) {
            RECT rcCheckBox;
            GetCheckBoxRect(i, rcCheckBox);

            if (event.Type == UIEVENT_BUTTONDOWN || event.Type == UIEVENT_DBLCLICK) {
                if (::PtInRect(&rcCheckBox, event.ptMouse)) {
                    m_uCheckBoxState |= UISTATE_PUSHED | UISTATE_CAPTURED;
                    Invalidate();
                }
            } else if (event.Type == UIEVENT_MOUSEMOVE) {
                if ((m_uCheckBoxState & UISTATE_CAPTURED) != 0) {
                    if (::PtInRect(&rcCheckBox, event.ptMouse)) {
                        m_uCheckBoxState |= UISTATE_PUSHED;
                    } else {
                        m_uCheckBoxState &= ~UISTATE_PUSHED;
                    }
                    Invalidate();
                }
            } else if (event.Type == UIEVENT_BUTTONUP) {
                if ((m_uCheckBoxState & UISTATE_CAPTURED) != 0) {
                    if (::PtInRect(&rcCheckBox, event.ptMouse)) {
                        SetCheck(!GetCheck());
                        if (m_pManager) {
                            m_pManager->SendNotify(this, DUI_MSGTYPE_LISTITEMCHECKED, MAKEWPARAM(GetIndex(), 0),
                                m_bChecked);
                        }
                    }
                    m_uCheckBoxState &= ~(UISTATE_PUSHED | UISTATE_CAPTURED);
                    Invalidate();
                }
            } else if (event.Type == UIEVENT_MOUSEENTER) {
                if (::PtInRect(&rcCheckBox, event.ptMouse)) {
                    m_uCheckBoxState |= UISTATE_HOT;
                    Invalidate();
                }
            } else if (event.Type == UIEVENT_MOUSELEAVE) {
                m_uCheckBoxState &= ~UISTATE_HOT;
                Invalidate();
            }
        }
    }

    CListLabelElementUI::DoEvent(event);
}

SIZE CListTextExtElementUI::EstimateSize(SIZE szAvailable)
{
    TListInfoUI *pInfo = nullptr;
    if (m_pOwner) {
        pInfo = m_pOwner->GetListInfo();
    }
    const int yStep = 8;
    SIZE cXY = m_cxyFixed;
    if (cXY.cy == 0 && m_pManager != nullptr && pInfo != nullptr &&
        m_pManager->GetFontInfo(pInfo->nFont) != nullptr) {
        cXY.cy = m_pManager->GetFontInfo(pInfo->nFont)->tm.tmHeight + yStep;
        cXY.cy += pInfo->rcTextPadding.top + pInfo->rcTextPadding.bottom;
    }

    return cXY;
}

void CListTextExtElementUI::DrawItemText(HDC hDC, const RECT &rcItem)
{
    if (m_pOwner == nullptr) {
        return;
    }
    TListInfoUI *pInfo = m_pOwner->GetListInfo();
    if (pInfo == nullptr) {
        return;
    }
    DWORD iTextColor = pInfo->dwTextColor;

    if ((m_uButtonState & UISTATE_HOT) != 0) {
        iTextColor = pInfo->dwHotTextColor;
    }
    if (IsSelected()) {
        iTextColor = pInfo->dwSelectedTextColor;
    }
    if (!IsEnabled()) {
        iTextColor = pInfo->dwDisabledTextColor;
    }
    IListCallbackUI *pCallback = m_pOwner->GetTextCallback();
    CListExUI *pListCtrl = reinterpret_cast<CListExUI *>(m_pOwner);
    if (pCallback == nullptr || pListCtrl == nullptr) {
        return;
    }
    m_nLinks = 0;
    int nLinks = lengthof(m_rcLinks);
    for (int i = 0; i < pInfo->nColumns; i++) {
        RECT rcItem = { pInfo->rcColumn[i].left, m_rcItem.top, pInfo->rcColumn[i].right, m_rcItem.bottom };

        DWORD iTextBkColor = 0;
        if (GetColumItemColor(i, iTextBkColor)) {
            CRenderEngine::DrawColor(hDC, rcItem, iTextBkColor);
        }

        rcItem.left += pInfo->rcTextPadding.left;
        rcItem.right -= pInfo->rcTextPadding.right;
        rcItem.top += pInfo->rcTextPadding.top;
        rcItem.bottom -= pInfo->rcTextPadding.bottom;

        // 检查是否需要显示CheckBox
        if (pListCtrl->CheckColumCheckBoxable(i)) {
            RECT rcCheckBox;
            GetCheckBoxRect(i, rcCheckBox);
            rcItem.left += (rcCheckBox.right - rcCheckBox.left);
        }

        CDuiString strText; // 不使用LPCTSTR，否则限制太多 by cddjr 2011/10/20
        if (pCallback) {
            strText = pCallback->GetItemText(this, m_iIndex, i);
        } else {
            strText.Assign(GetText(i));
        }
        if (pInfo->bShowHtml) {
            CRenderEngine::DrawHtmlText(hDC, m_pManager, rcItem, strText.GetData(), iTextColor, pInfo->nFont,
                &m_rcLinks[m_nLinks], &m_sLinks[m_nLinks], nLinks, DT_SINGLELINE | pInfo->uTextStyle);
        } else {
            CRenderEngine::DrawText(hDC, m_pManager, rcItem, strText.GetData(), iTextColor, pInfo->nFont,
                DT_SINGLELINE | pInfo->uTextStyle);
        }

        m_nLinks += nLinks;
        nLinks = static_cast<int>(lengthof(m_rcLinks) - m_nLinks);
    }
    for (int i = m_nLinks; i < lengthof(m_rcLinks); i++) {
        ::ZeroMemory(m_rcLinks + i, sizeof(RECT));
        (reinterpret_cast<CDuiString *>(m_sLinks + i))->Empty();
    }
}
void CListTextExtElementUI::PaintStatusImage(HDC hDC)
{
    if (m_pOwner == nullptr) {
        return;
    }
    CListExUI *pListCtrl = reinterpret_cast<CListExUI *>(m_pOwner);
    TListInfoUI *pInfo = m_pOwner->GetListInfo();
    if (pListCtrl == nullptr || pInfo == nullptr) {
        return;
    }
    for (int i = 0; i < pInfo->nColumns; i++) {
        if (pListCtrl->CheckColumCheckBoxable(i)) {
            RECT rcCheckBox;
            GetCheckBoxRect(i, rcCheckBox);

            m_uCheckBoxState &= ~UISTATE_PUSHED;

            if ((m_uCheckBoxState & UISTATE_SELECTED) != 0) {
                if (!m_sCheckBoxSelectedImage.IsEmpty()) {
                    if (!DrawCheckBoxImage(hDC, (LPCTSTR)m_sCheckBoxSelectedImage, nullptr, rcCheckBox)) {
                    } else {
                        goto Label_ForeImage;
                    }
                }
            }

            if (IsFocused()) {
                m_uCheckBoxState |= UISTATE_FOCUSED;
            } else {
                m_uCheckBoxState &= ~UISTATE_FOCUSED;
            }
            if (!IsEnabled()) {
                m_uCheckBoxState |= UISTATE_DISABLED;
            } else {
                m_uCheckBoxState &= ~UISTATE_DISABLED;
            }

            if ((m_uCheckBoxState & UISTATE_DISABLED) != 0) {
                if (!m_sCheckBoxDisabledImage.IsEmpty()) {
                    if (!DrawCheckBoxImage(hDC, (LPCTSTR)m_sCheckBoxDisabledImage, nullptr, rcCheckBox)) {
                    } else {
                        return;
                    }
                }
            } else if ((m_uCheckBoxState & UISTATE_PUSHED) != 0) {
                if (!m_sCheckBoxPushedImage.IsEmpty()) {
                    if (!DrawCheckBoxImage(hDC, (LPCTSTR)m_sCheckBoxPushedImage, nullptr, rcCheckBox)) {
                    } else {
                        return;
                    }
                }
            } else if ((m_uCheckBoxState & UISTATE_HOT) != 0) {
                if (!m_sCheckBoxHotImage.IsEmpty()) {
                    if (!DrawCheckBoxImage(hDC, (LPCTSTR)m_sCheckBoxHotImage, nullptr, rcCheckBox)) {
                    } else {
                        return;
                    }
                }
            } else if ((m_uCheckBoxState & UISTATE_FOCUSED) != 0) {
                if (!m_sCheckBoxFocusedImage.IsEmpty()) {
                    if (!DrawCheckBoxImage(hDC, (LPCTSTR)m_sCheckBoxFocusedImage, nullptr, rcCheckBox)) {
                    } else {
                        return;
                    }
                }
            }

            if (!m_sCheckBoxNormalImage.IsEmpty()) {
                if (!DrawCheckBoxImage(hDC, (LPCTSTR)m_sCheckBoxNormalImage, nullptr, rcCheckBox)) {
                } else {
                    return;
                }
            }

        Label_ForeImage:
            if (!m_sCheckBoxForeImage.IsEmpty()) {
                if (!DrawCheckBoxImage(hDC, (LPCTSTR)m_sCheckBoxForeImage, nullptr, rcCheckBox)) {
                }
            }
        }
    }
}
BOOL CListTextExtElementUI::DrawCheckBoxImage(HDC hDC, LPCTSTR pStrImage, LPCTSTR pStrModify, RECT &rcCheckBox)
{
    return CRenderEngine::DrawImageString(hDC, m_pManager, rcCheckBox, m_rcPaint, pStrImage, pStrModify);
}
void CListTextExtElementUI::SetAttribute(LPCTSTR pstrName, LPCTSTR pstrValue)
{
    if (_tcsicmp(pstrName, _T("checkboxwidth")) == 0) {
        SetCheckBoxWidth(_ttoi(pstrValue));
    } else if (_tcsicmp(pstrName, _T("checkboxheight")) == 0) {
        SetCheckBoxHeight(_ttoi(pstrValue));
    } else if (_tcsicmp(pstrName, _T("checkboxnormalimage")) == 0) {
        SetCheckBoxNormalImage(pstrValue);
    } else if (_tcsicmp(pstrName, _T("checkboxhotimage")) == 0) {
        SetCheckBoxHotImage(pstrValue);
    } else if (_tcsicmp(pstrName, _T("checkboxpushedimage")) == 0) {
        SetCheckBoxPushedImage(pstrValue);
    } else if (_tcsicmp(pstrName, _T("checkboxfocusedimage")) == 0) {
        SetCheckBoxFocusedImage(pstrValue);
    } else if (_tcsicmp(pstrName, _T("checkboxdisabledimage")) == 0) {
        SetCheckBoxDisabledImage(pstrValue);
    } else if (_tcsicmp(pstrName, _T("checkboxselectedimage")) == 0) {
        SetCheckBoxSelectedImage(pstrValue);
    } else if (_tcsicmp(pstrName, _T("checkboxforeimage")) == 0) {
        SetCheckBoxForeImage(pstrValue);
    } else {
        CListLabelElementUI::SetAttribute(pstrName, pstrValue);
    }
}
LPCTSTR CListTextExtElementUI::GetCheckBoxNormalImage()
{
    return m_sCheckBoxNormalImage;
}

void CListTextExtElementUI::SetCheckBoxNormalImage(LPCTSTR pStrImage)
{
    m_sCheckBoxNormalImage = pStrImage;
}

LPCTSTR CListTextExtElementUI::GetCheckBoxHotImage()
{
    return m_sCheckBoxHotImage;
}

void CListTextExtElementUI::SetCheckBoxHotImage(LPCTSTR pStrImage)
{
    m_sCheckBoxHotImage = pStrImage;
}

LPCTSTR CListTextExtElementUI::GetCheckBoxPushedImage()
{
    return m_sCheckBoxPushedImage;
}

void CListTextExtElementUI::SetCheckBoxPushedImage(LPCTSTR pStrImage)
{
    m_sCheckBoxPushedImage = pStrImage;
}

LPCTSTR CListTextExtElementUI::GetCheckBoxFocusedImage()
{
    return m_sCheckBoxFocusedImage;
}

void CListTextExtElementUI::SetCheckBoxFocusedImage(LPCTSTR pStrImage)
{
    m_sCheckBoxFocusedImage = pStrImage;
}

LPCTSTR CListTextExtElementUI::GetCheckBoxDisabledImage()
{
    return m_sCheckBoxDisabledImage;
}

void CListTextExtElementUI::SetCheckBoxDisabledImage(LPCTSTR pStrImage)
{
    m_sCheckBoxDisabledImage = pStrImage;
}
LPCTSTR CListTextExtElementUI::GetCheckBoxSelectedImage()
{
    return m_sCheckBoxSelectedImage;
}

void CListTextExtElementUI::SetCheckBoxSelectedImage(LPCTSTR pStrImage)
{
    m_sCheckBoxSelectedImage = pStrImage;
}
LPCTSTR CListTextExtElementUI::GetCheckBoxForeImage()
{
    return m_sCheckBoxForeImage;
}

void CListTextExtElementUI::SetCheckBoxForeImage(LPCTSTR pStrImage)
{
    m_sCheckBoxForeImage = pStrImage;
}

void CListTextExtElementUI::DoPaint(HDC hDC, const RECT &rcPaint)
{
    if (!::IntersectRect(&m_rcPaint, &rcPaint, &m_rcItem))
        return;
    DrawItemBk(hDC, m_rcItem);
    PaintStatusImage(hDC);
    DrawItemText(hDC, m_rcItem);
}
void CListTextExtElementUI::GetCheckBoxRect(int nIndex, RECT &rc)
{
    const int lfStep = 6;
    const int multiples = 2;
    SecureZeroMemory(&rc, sizeof(rc));
    int nItemHeight = m_rcItem.bottom - m_rcItem.top;
    rc.left = m_rcItem.left + lfStep;
    rc.top = m_rcItem.top + (nItemHeight - GetCheckBoxHeight()) / multiples;
    rc.right = rc.left + GetCheckBoxWidth();
    rc.bottom = rc.top + GetCheckBoxHeight();
}
int CListTextExtElementUI::GetCheckBoxWidth() const
{
    return m_cxyCheckBox.cx;
}

void CListTextExtElementUI::SetCheckBoxWidth(int cx)
{
    if (cx < 0) {
        return;
    }
    m_cxyCheckBox.cx = cx;
}

int CListTextExtElementUI::GetCheckBoxHeight() const
{
    return m_cxyCheckBox.cy;
}

void CListTextExtElementUI::SetCheckBoxHeight(int cy)
{
    if (cy < 0) {
        return;
    }
    m_cxyCheckBox.cy = cy;
}

void CListTextExtElementUI::SetCheck(BOOL bCheck)
{
    if (m_bChecked == bCheck) {
        return;
    }
    m_bChecked = bCheck;
    if (m_bChecked) {
        m_uCheckBoxState |= UISTATE_SELECTED;
    } else {
        m_uCheckBoxState &= ~UISTATE_SELECTED;
    }
    Invalidate();
}

BOOL CListTextExtElementUI::GetCheck() const
{
    return m_bChecked;
}

int CListTextExtElementUI::HitTestColum(POINT ptMouse)
{
    const int ret = -1;
    TListInfoUI *pInfo = m_pOwner->GetListInfo();
    if (pInfo == nullptr) {
        return ret;
    }
    for (int i = 0; i < pInfo->nColumns; i++) {
        RECT rcItem = { pInfo->rcColumn[i].left, m_rcItem.top, pInfo->rcColumn[i].right, m_rcItem.bottom };
        rcItem.left += pInfo->rcTextPadding.left;
        rcItem.right -= pInfo->rcTextPadding.right;
        rcItem.top += pInfo->rcTextPadding.top;
        rcItem.bottom -= pInfo->rcTextPadding.bottom;

        if (::PtInRect(&rcItem, ptMouse)) {
            return i;
        }
    }
    return -1;
}

BOOL CListTextExtElementUI::CheckColumEditable(int nColum)
{
    if (m_pOwner == nullptr) {
        return FALSE;
    }
    return m_pOwner->CheckColumEditable(nColum);
}
void CListTextExtElementUI::GetColumRect(int nColum, RECT &rc)
{
    TListInfoUI *pInfo = m_pOwner->GetListInfo();
    if (pInfo == nullptr) {
        return;
    }
    rc.left = pInfo->rcColumn[nColum].left;
    rc.top = m_rcItem.top;
    rc.right = pInfo->rcColumn[nColum].right;
    rc.bottom = m_rcItem.bottom;
}

void CListTextExtElementUI::SetColumItemColor(int nColum, DWORD iBKColor)
{
    ColumCorlorArray[nColum].bEnable = TRUE;
    ColumCorlorArray[nColum].iBKColor = iBKColor;
    Invalidate();
}
BOOL CListTextExtElementUI::GetColumItemColor(int nColum, DWORD &iBKColor)
{
    if (!ColumCorlorArray[nColum].bEnable) {
        return FALSE;
    }
    iBKColor = ColumCorlorArray[nColum].iBKColor;
    return TRUE;
}
} // namespace DuiLib
